﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace CompilerForC.SyntaxAnalysis
{
    using LexicalAnalysis;
    using TreeCollection;
    
    /// <summary>
    /// Class used to parse token stream using syntax rules of the simplified
    /// C language. If parsing succeeds, parse tree is returned. If input token
    /// stream contains errors, syntax error list is filled and can be used to
    /// output diagnostic informations.
    /// 
    /// For syntax rules, refer to the Grammar.txt document.
    /// </summary>
    public class Parser
    {
        #region Events and Delegates

        /// <summary>
        /// Delegate for the method used to parse non-terminal grammar symbol.
        /// </summary>
        private delegate void ParseMethodDelegate(TreeNode<SyntaxNode> parent);

        #endregion Events and Delegates

        #region Private Fields

        /// <summary>
        /// Tables filled by the lexical analyzer.
        /// </summary>
        private LexerTables _lexerTables;
        /// <summary>
        /// Used to iterate over stream of tokens.
        /// </summary>
        private TokenStream _tokenStream;
        /// <summary>
        /// Counts nodes added to the parse tree. Used to assign unique node ids.
        /// </summary>
        private int _parseTreeNodeCounter;
        /// <summary>
        /// Parse tree root node.
        /// </summary>
        private TreeNode<SyntaxNode> _parseTreeRootNode = new TreeNode<SyntaxNode>();
        /// <summary>
        /// List of syntax errors found during parsing.
        /// </summary>
        private List<SyntaxError> _syntaxErrors = new List<SyntaxError>();

        #endregion Private Fields

        #region Public Properties

        /// <summary>
        /// Gets tables filled by the lexical analyzer.
        /// </summary>
        public LexerTables LexerTables
        {
            get { return _lexerTables; }
        }

        /// <summary>
        /// Gets parse tree root node.
        /// </summary>
        public TreeNode<SyntaxNode> ParseTreeRootNode
        {
            get { return _parseTreeRootNode; }
        }

        /// <summary>
        /// Gets list of syntax errors found during parsing.
        /// </summary>
        public List<SyntaxError> SyntaxErrors
        {
            get { return _syntaxErrors; }
        }

        #endregion Public Properties

        #region Public Methods

        /// <summary>
        /// Parses token stream and creates parse tree.
        /// </summary>
        /// <param name="lexerTables">Tables filled by the lexical analyzer.</param>
        /// <returns>True if input token stream contains no syntax errors.</returns>
        public bool Parse(LexerTables lexerTables)
        {
            Debug.Assert(lexerTables != null);

            _lexerTables = lexerTables;
            _tokenStream = new TokenStream(_lexerTables);
            _parseTreeNodeCounter = 0;

            bool error = false;

            try
            {
                ParseTranslationUnit();
                ReduceParseTree();
            }
            catch (TokenStreamException)
            {
                error = true;
            }

            // All tokens in the stream parsed?
            if (_tokenStream.CurrentIndex != _lexerTables.Tokens.Count || error)
                AddSyntaxError(0, "Unexpected end of program.");

            return _syntaxErrors.Count == 0;
        }

        #endregion Public Methods

        #region Non-Terminal Parsing Methods

        /// <summary>
        /// 1. translation_unit -> external_declaration translation_unit_1
        /// </summary>
        private void ParseTranslationUnit()
        {
            _parseTreeRootNode = AddRootNode("translation_unit");

            ParseExternalDeclaration(_parseTreeRootNode);
            ParseTranslationUnit1(_parseTreeRootNode);
        }

        /// <summary>
        /// 2. translation_unit_1 -> external_declaration translation_unit_1 | epsilon
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        public void ParseTranslationUnit1(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "translation_unit_1");

            if (!_tokenStream.CanAdvance)
            {
                AddEpsilonNode(node);
                return;
            }

            Token token = _tokenStream.CurrentToken;

            if (IsFirstExternalDeclarationToken(token))
            {
                ParseExternalDeclaration(node);
                ParseTranslationUnit1(node);
            }
            else
            {
                AddEpsilonNode(node);                    
            }
        }

        /// <summary>
        /// 3. external_declaration -> type_specifier IDENTIFIER external_declaration_1 | struct_definition
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseExternalDeclaration(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "external_declaration");

            Token token = _tokenStream.CurrentToken;

            if (IsFirstTypeSpecifierToken(token))
            {
                ParseTypeSpecifier(node);

                token = _tokenStream.Advance();

                if (token.Type != TokenType.Identifier)
                {
                    AddSyntaxError(token.LineNumber, "Identifier expected.");
                }
                else
                {
                    AddTerminalNode(node, token);
                }

                ParseExternalDeclaration1(node);
            }
            else
            {
                ParseStructDefinition(node);
            }
        }
        
        /// <summary>
        /// 4. external_declaration_1 -> function_tail | variable_tail
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseExternalDeclaration1(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "external_declaration_1");

            Token token = _tokenStream.CurrentToken;

            if (IsFirstFunctionTailToken(token))
            {
                ParseFunctionTail(node);
            }
            else
            {
                ParseVariableTail(node);
            }
        }

        /// <summary>
        /// 5. function_tail ->	'(' parameter_list ')' compound_statement
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseFunctionTail(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "function_tail");

            ParseMethodDelegate Recover = delegate (TreeNode<SyntaxNode> p)
            {
                _tokenStream.CurrentIndex--;

                int index = _tokenStream.Find("{");

                if (index != -1)
                {
                    _tokenStream.CurrentIndex = index;
                    ParseCompoundStatement(p);
                }
                else
                {
                    index = _tokenStream.Find("}");

                    if (index != -1)
                    {
                        AddSyntaxError(_tokenStream.CurrentToken.LineNumber, "Missing opening brace.");

                        _tokenStream.CurrentIndex = index + 1;
                    }                       
                }
            };

            Token token = _tokenStream.Advance();

            if (!GetTokenValue(token).Equals("("))
            {
                AddSyntaxError(token.LineNumber, "Expected '(' before function parameter list.");
                Recover(node); return;
            }
            else
            {
                AddTerminalNode(node, token);
            }
            
            ParseParameterList(node);

            token = _tokenStream.Advance();

            if (!GetTokenValue(token).Equals(")"))
            {
                AddSyntaxError(token.LineNumber, "Expected ')' after function parameter list.");
                Recover(node); return;
            }
            else
            {
                AddTerminalNode(node, token);
            }

            ParseCompoundStatement(node);
        }

        /// <summary>
        /// 6. variable_tail ->	array_specifier variable_tail_1
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseVariableTail(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "variable_tail");

            ParseArraySpecifier(node);
            ParseVariableTail1(node);
        }

        /// <summary>
        /// 7. variable_tail_1 -> ';' | '=' initializer ';'
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseVariableTail1(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "variable_tail_1");

            Token token = _tokenStream.CurrentToken;

            if (GetTokenValue(token).Equals("="))
            {
                AddTerminalNode(node, token);

                _tokenStream.Advance();
                ParseInitializer(node);
            }

            token = _tokenStream.Advance();

            if (!GetTokenValue(token).Equals(";"))
            {
                _tokenStream.CurrentIndex--;
                AddSyntaxError(token.LineNumber, "Missing ';'.");
            }
            else
            {
                AddTerminalNode(node, token);
            }
        }

        /// <summary>
        /// 8. type_specifier -> 'void' | 'char' | 'int' | 'float' | 'double' | struct_specifier | IDENTIFIER
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseTypeSpecifier(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "type_specifier");

            Token token = _tokenStream.Advance();

            if (!IsFirstTypeSpecifierToken(token))
            {
                AddSyntaxError(token.LineNumber, String.Format("'{0}' is unrecognized type.", GetTokenValue(token)));
            }
            else
            {
                AddTerminalNode(node, token);
            }
        }

        /// <summary>
        /// 9. declarator -> type_specifier IDENTIFIER array_specifier
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseDeclarator(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "declarator");

            ParseTypeSpecifier(node);

            Token token = _tokenStream.Advance();

            if (token.Type != TokenType.Identifier)
            {
                AddSyntaxError(token.LineNumber, "Expected identifier after type.");
            }
            else
            {
                AddTerminalNode(node, token);
            }

            ParseArraySpecifier(node);
        }

        /// <summary>
        /// 10.	array_specifier	-> '[' constant_expression ']' array_specifier | epsilon
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseArraySpecifier(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "array_specifier");

            if (GetTokenValue(_tokenStream.CurrentToken).Equals("["))
            {
                AddTerminalNode(node, _tokenStream.CurrentToken);
                _tokenStream.Advance();
                
                ParseConstantExpression(node);

                Token token = _tokenStream.Advance();
               
                if (!GetTokenValue(token).Equals("]"))
                {
                    AddSyntaxError(token.LineNumber, "Missing closing bracket for the array specifier.");
                }
                else
                {
                    AddTerminalNode(node, token);
                }

                ParseArraySpecifier(node);
            }
            else
            {
                AddEpsilonNode(node);
            }
        }
        
        /// <summary>
        /// 11.	declaration	-> declarator variable_tail_1
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseDeclaration(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "declaration");

            ParseDeclarator(node);
            ParseVariableTail1(node);
        }

        /// <summary>
        /// 12.	struct_definition -> 'struct' IDENTIFIER '{' declaration_list '}' ';'
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseStructDefinition(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "struct_definition");
                        
            Token token = _tokenStream.Advance();

            if (!GetTokenValue(token).Equals("struct"))
            {
                AddSyntaxError(token.LineNumber, "Expected 'struct'.");
            }
            else
            {
                AddTerminalNode(node, token);
            }

            token = _tokenStream.Advance();

            if (token.Type != TokenType.Identifier)
            {
                AddSyntaxError(token.LineNumber, "Structure definition requires valid identifier.");
            }
            else
            {
                AddTerminalNode(node, token);
            }

            token = _tokenStream.Advance();

            if (!GetTokenValue(token).Equals("{"))
            {
                AddSyntaxError(token.LineNumber, "Missing opening brace before the structure body.");
            }
            else
            {
                AddTerminalNode(node, token);
            }

            ParseStructDeclarationList(node);

            token = _tokenStream.Advance();

            if (!GetTokenValue(token).Equals("}"))
            {
                AddSyntaxError(token.LineNumber, "Missing closing brace after the structure body.");
            }
            else
            {
                AddTerminalNode(node, token);
            }

            token = _tokenStream.Advance();

            if (!GetTokenValue(token).Equals(";"))
            {
                _tokenStream.CurrentIndex--;
                AddSyntaxError(token.LineNumber, "Expected ';' after the structure definition.");
            }
            else
            {
                AddTerminalNode(node, token);
            }
        }

        /// <summary>
        /// 13.	struct_declaration_list -> declaration_list | epsilon
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseStructDeclarationList(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "struct_declaration_list");

            if (IsFirstDeclarationListToken(_tokenStream.CurrentToken))
            {
                ParseDeclarationList(node);
            }
            else
            {
                AddEpsilonNode(node);
            }
        }

        /// <summary>
        /// 14.	initializer	-> assignment_expression | '{' initializer_list '}'
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseInitializer(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "initializer");

            if (GetTokenValue(_tokenStream.CurrentToken).Equals("{"))
            {
                AddTerminalNode(node, _tokenStream.CurrentToken);

                _tokenStream.Advance();

                ParseInitializerList(node);

                Token token = _tokenStream.Advance();

                if (!GetTokenValue(token).Equals("}"))
                {
                    AddSyntaxError(token.LineNumber, "Missing closing brace after the initializer list.");
                }
                else
                {
                    AddTerminalNode(node, token);
                }
            }
            else
            {
                ParseAssignmentExpression(node);  
            }
        }

        /// <summary>
        /// 15.	initializer_list -> initializer initializer_list_1
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseInitializerList(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "initializer_list");

            ParseInitializer(node);
            ParseInitializerList1(node);
        }

        /// <summary>
        /// 16.	initializer_list_1 -> ',' initializer initializer_list_1 | epsilon
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseInitializerList1(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "initializer_list_1");

            if (GetTokenValue(_tokenStream.CurrentToken).Equals(","))
            {
                AddTerminalNode(node, _tokenStream.CurrentToken);

                _tokenStream.Advance();
                
                ParseInitializer(node);
                ParseInitializerList1(node);
            }
            else
            {
                AddEpsilonNode(node);
            }
        }

        /// <summary>
        /// 17.	declaration_list -> declaration declaration_list_1
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseDeclarationList(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "declaration_list");

            ParseDeclaration(node);
            ParseDeclarationList1(node);
        }

        /// <summary>
        /// 18.	declaration_list_1 -> declaration declaration_list_1 | epsilon
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseDeclarationList1(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "declaration_list_1");

            if (IsFirstDeclarationToken(_tokenStream.CurrentToken))
            {
                ParseDeclaration(node);
                ParseDeclarationList1(node);
            }
            else
            {
                AddEpsilonNode(node);
            }
        }

        /// <summary>
        /// 19.	parameter_list -> declarator parameter_list_1 | epsilon
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseParameterList(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "parameter_list");

            if (IsFirstDeclaratorToken(_tokenStream.CurrentToken))
            {
                ParseDeclarator(node);
                ParseParameterList1(node);
            }
            else
            {
                AddEpsilonNode(node);
            }
        }

        /// <summary>
        /// 20.	parameter_list_1 ->	',' declarator parameter_list_1 | epsilon
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseParameterList1(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "parameter_list_1");

            if (GetTokenValue(_tokenStream.CurrentToken).Equals(","))
            {
                AddTerminalNode(node, _tokenStream.CurrentToken);

                _tokenStream.Advance();

                ParseDeclarator(node);
                ParseParameterList1(node);
            }
            else
            {
                AddEpsilonNode(node);
            }
        }

        /// <summary>
        /// 21.	statement -> compound_statement | expression_statement | selection_statement | iteration_statement | jump_statement | labeled_statement
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseStatement(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "statement");

            Token token = _tokenStream.CurrentToken;

            if (IsFirstCompoundStatementToken(token))
            {
                ParseCompoundStatement(node);
            }
            else if (IsFirstSelectionStatementToken(token))
            {
                ParseSelectionStatement(node);
            }
            else if (IsFirstIterationStatementToken(token))
            {
                ParseIterationStatement(node);
            }
            else if (IsFirstJumpStatementToken(token))
            {
                ParseJumpStatement(node);
            }
            else if (IsFirstLabeledStatementToken(token))
            {
                ParseLabeledStatement(node);
            }
            else
            {
                ParseExpressionStatement(node);
            }
        }

        /// <summary>
        /// 22.	statement_list -> statement statement_list_1
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseStatementList(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "statement_list");

            ParseStatement(node);
            ParseStatementList1(node);
        }

        /// <summary>
        /// 23.	statement_list_1 -> statement statement_list_1 | epsilon
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseStatementList1(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "statement_list_1");

            if (IsFirstStatementToken(_tokenStream.CurrentToken))
            {
                ParseStatement(node);
                ParseStatementList1(node);
            }
            else
            {
                AddEpsilonNode(node);
            }
        }
        
        /// <summary>
        /// 24. compound_statement -> '{' compound_statement_1
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseCompoundStatement(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "compound_statement");

            Token token = _tokenStream.Advance();

            if (!GetTokenValue(token).Equals("{"))
            {
                AddSyntaxError(token.LineNumber, "Closing brace mismatch. Expected '{'.");
            }
            else
            {
                AddTerminalNode(node, token);
            }

            ParseCompoundStatement1(node);
        }

        /// <summary>
        /// 25.	compound_statement_1 ->	'}' | statement_list '}' | declaration_list compound_statement_2
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseCompoundStatement1(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "compound_statement_1");

            if (GetTokenValue(_tokenStream.CurrentToken).Equals("}"))
            {
                Token token = _tokenStream.Advance();
                AddTerminalNode(node, token);
            }
            else if (IsFirstDeclarationListToken(_tokenStream.CurrentToken))
            {
                ParseDeclarationList(node);
                ParseCompoundStatement2(node);
            }
            else
            {
                ParseStatementList(node);

                Token token = _tokenStream.Advance();

                if (!GetTokenValue(token).Equals("}"))
                {
                    AddSyntaxError(token.LineNumber, "Opening brace mismatch. Expected '}'.");
                }
                else
                {
                    AddTerminalNode(node, token);
                }
            }
        }

        /// <summary>
        /// 26.	compound_statement_2 -> '}' | statement_list '}'
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseCompoundStatement2(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "compound_statement_2");

            if (GetTokenValue(_tokenStream.CurrentToken).Equals("}"))
            {
                Token token = _tokenStream.Advance();
                AddTerminalNode(node, token);
            }
            else
            {
                ParseStatementList(node);

                Token token = _tokenStream.Advance();

                if (!GetTokenValue(token).Equals("}"))
                {
                    AddSyntaxError(token.LineNumber, "Opening brace mismatch. Expected '}'.");
                }
                else
                {
                    AddTerminalNode(node, token);
                }
            }
        }
        
        /// <summary>
        /// 27.	expression_statement ->	';' | expression ';'
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseExpressionStatement(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "expression_statement");

            if (GetTokenValue(_tokenStream.CurrentToken).Equals(";"))
            {
                Token token = _tokenStream.Advance();
                AddTerminalNode(node, token);
            }
            else
            {
                ParseExpression(node);

                Token token = _tokenStream.Advance();

                if (!GetTokenValue(token).Equals(";"))
                {
                    _tokenStream.CurrentIndex--;
                    AddSyntaxError(token.LineNumber, "Missing ';' after the expression.");
                }
                else
                {
                    AddTerminalNode(node, token);
                }
            }
        }

        /// <summary>
        /// 28.	selection_statement	-> if_selection_statement | switch_selection_statement
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseSelectionStatement(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "selection_statement");

            if (IsFirstIfSelectionStatementToken(_tokenStream.CurrentToken))
            {
                ParseIfSelectionStatement(node);
            }
            else
            {
                ParseSwitchSelectionStatement(node);
            }
        }

        /// <summary>
        /// 29.	if_selection_statement -> 'if' '(' expression ')' statement if_selection_statement_1
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseIfSelectionStatement(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "if_selection_statement");

            Token token = _tokenStream.Advance();
            AddTerminalNode(node, token);

            token = _tokenStream.Advance();

            if (!GetTokenValue(token).Equals("("))
            {
                AddSyntaxError(token.LineNumber, "Missing '(' after 'if'.");
            }
            else
            {
                AddTerminalNode(node, token);
            }

            ParseExpression(node);

            token = _tokenStream.Advance();

            if (!GetTokenValue(token).Equals(")"))
            {
                AddSyntaxError(token.LineNumber, "Missing ')' after 'if'.");
            }
            else
            {
                AddTerminalNode(node, token);
            }

            ParseStatement(node);
            ParseIfSelectionStatement1(node);
        }
        
        /// <summary>
        /// 30.	if_selection_statement_1 -> 'else' statement | epsilon
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseIfSelectionStatement1(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "if_selection_statement_1");

            if (GetTokenValue(_tokenStream.CurrentToken).Equals("else"))
            {
                Token token = _tokenStream.Advance();
                AddTerminalNode(node, token);

                ParseStatement(node);
            }
            else
            {
                AddEpsilonNode(node);
            }
        }

        /// <summary>
        /// 31.	switch_selection_statement -> 'switch' '(' expression ')' statement
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseSwitchSelectionStatement(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "switch_selection_statement");

            Token token = _tokenStream.Advance();

            if (!GetTokenValue(token).Equals("switch"))
            {
                AddSyntaxError(token.LineNumber, "Expected 'switch'.");
            }
            else
            {
                AddTerminalNode(node, token);
            }

            token = _tokenStream.Advance();

            if (!GetTokenValue(token).Equals("("))
            {
                AddSyntaxError(token.LineNumber, "Missing '(' after 'switch'.");
            }
            else
            { 
                AddTerminalNode(node, token); 
            }

            ParseExpression(node);

            token = _tokenStream.Advance();

            if (!GetTokenValue(token).Equals(")"))
            {
                AddSyntaxError(token.LineNumber, "Missing ')' after 'switch'.");
            }
            else
            {
                AddTerminalNode(node, token);
            }

            ParseStatement(node);
        }

        /// <summary>
        /// 32.	iteration_statement	-> while_iteration_statement | do_iteration_statement | for_iteration_statement
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseIterationStatement(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "iteration_statement");

            if (IsFirstWhileIterationStatementToken(_tokenStream.CurrentToken))
            {
                ParseWhileIterationStatement(node);
            }
            else if (IsFirstDoIterationStatementToken(_tokenStream.CurrentToken))
            {
                ParseDoIterationStatement(node);
            }
            else
            {
                ParseForIterationStatement(node);
            }
        }

        /// <summary>
        /// 33. while_iteration_statement -> 'while' '(' expression ')' statement
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseWhileIterationStatement(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "while_iteration_statement");

            Token token = _tokenStream.Advance();
            AddTerminalNode(node, token);

            token = _tokenStream.Advance();

            if (!GetTokenValue(token).Equals("("))
            {
                AddSyntaxError(token.LineNumber, "Missing '(' after 'while'.");
            }
            else
            {
                AddTerminalNode(node, token);
            }

            ParseExpression(node);

            token = _tokenStream.Advance();

            if (!GetTokenValue(token).Equals(")"))
            {
                AddSyntaxError(token.LineNumber, "Missing ')' after 'while'.");
            }
            else
            {
                AddTerminalNode(node, token);
            }

            ParseStatement(node);
        }

        /// <summary>
        /// 34. do_iteration_statement -> 'do' statement 'while' '(' expression ')' ';'
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseDoIterationStatement(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "do_iteration_statement");

            Token token = _tokenStream.Advance();
            AddTerminalNode(node, token);

            ParseStatement(node);

            token = _tokenStream.Advance();

            if (!GetTokenValue(token).Equals("while"))
            {
                AddSyntaxError(token.LineNumber, "Missing 'while'.");
            }
            else
            {
                AddTerminalNode(node, token);
            }

            token = _tokenStream.Advance();

            if (!GetTokenValue(token).Equals("("))
            {
                AddSyntaxError(token.LineNumber, "Missing '(' after 'while'.");
            }
            else
            {
                AddTerminalNode(node, token);
            }

            ParseExpression(node);

            token = _tokenStream.Advance();

            if (!GetTokenValue(token).Equals(")"))
            {
                AddSyntaxError(token.LineNumber, "Missing ')' after 'while'.");
            }
            else
            {
                AddTerminalNode(node, token);
            }

            token = _tokenStream.Advance();

            if (!GetTokenValue(token).Equals(";"))
            {
                _tokenStream.CurrentIndex--;
                AddSyntaxError(token.LineNumber, "Missing ';' after 'while'.");
            }
            else
            {
                AddTerminalNode(node, token);
            }
        }

        /// <summary>
        /// 35. for_iteration_statement	-> 'for' '(' expression_statement expression_statement for_iteration_statement_1
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseForIterationStatement(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "for_iteration_statement");

            Token token = _tokenStream.Advance();

            if (!GetTokenValue(token).Equals("for"))
            {
                AddSyntaxError(token.LineNumber, "Expected 'for'.");
            }
            else
            {
                AddTerminalNode(node, token);
            }

            token = _tokenStream.Advance();

            if (!GetTokenValue(token).Equals("("))
            {
                AddSyntaxError(token.LineNumber, "Missing '(' after 'for'.");
            }
            else
            {
                AddTerminalNode(node, token);
            }

            ParseExpressionStatement(node);
            ParseExpressionStatement(node);
            ParseForIterationStatement1(node);
        }

        /// <summary>
        /// 36.	for_iteration_statement_1 -> ')' statement | expression ')' statement
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseForIterationStatement1(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "for_iteration_statement_1");

            Token token = _tokenStream.CurrentToken;

            if (GetTokenValue(token).Equals(")"))
            {
                token = _tokenStream.Advance();

                if (!GetTokenValue(token).Equals(")"))
                {
                    AddSyntaxError(token.LineNumber, "Missing ')' after 'for'.");
                }
                else
                {
                    AddTerminalNode(node, token);
                }

                ParseStatement(node);
            }
            else if (IsFirstExpressionStatementToken(token))
            {
                ParseExpression(node);

                token = _tokenStream.Advance();

                if (!GetTokenValue(token).Equals(")"))
                {
                    AddSyntaxError(token.LineNumber, "Missing ')' after 'for'.");
                }
                else
                {
                    AddTerminalNode(node, token);
                }

                ParseStatement(node);
            }
            else
            {
                AddSyntaxError(token.LineNumber, "Expected expression or ')'.");
            }
        }

        /// <summary>
        /// 37.	jump_statement -> 'continue' ';' | 'break' ';' | 'return' jump_statement_1
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseJumpStatement(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "jump_statement");

            Token token = _tokenStream.Advance();
            AddTerminalNode(node, token);

            string value = GetTokenValue(token);

            if (value.Equals("continue"))
            {
                token = _tokenStream.Advance();

                if (!GetTokenValue(token).Equals(";"))
                {
                    _tokenStream.CurrentIndex--;
                    AddSyntaxError(token.LineNumber, "Missing ';' after 'continue'.");
                }
                else
                {
                    AddTerminalNode(node, token);
                }
            }
            else if (value.Equals("break"))
            {
                token = _tokenStream.Advance();

                if (!GetTokenValue(token).Equals(";"))
                {
                    _tokenStream.CurrentIndex--;
                    AddSyntaxError(token.LineNumber, "Missing ';' after 'break'.");
                }
                else
                {
                    AddTerminalNode(node, token);
                }
            }
            else
            {
                ParseJumpStatement1(node);
            }
        }

        /// <summary>
        /// 38.	jump_statement_1 ->	';' | expression ';'
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseJumpStatement1(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "jump_statement_1");

            Token token = _tokenStream.CurrentToken;
            
            if (GetTokenValue(token).Equals(";"))
            {
                _tokenStream.Advance();
                AddTerminalNode(node, token);
            }
            else if (IsFirstExpressionStatementToken(token))
            {
                ParseExpression(node);

                token = _tokenStream.Advance();

                if (!GetTokenValue(token).Equals(";"))
                {
                    _tokenStream.CurrentIndex--;
                    AddSyntaxError(token.LineNumber, "Missing ';' after expression.");
                }
                else
                {
                    AddTerminalNode(node, token);
                }
            }
            else
            {
                AddSyntaxError(token.LineNumber, "Expected ';' or expression.");
            }
        }
                
        /// <summary>
        /// 39.	labeled_statement -> 'case' constant_expression ':' statement | 'default' ':' statement
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseLabeledStatement(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "labeled_statement");

            Token token = _tokenStream.Advance();
            AddTerminalNode(node, token);

            string value = GetTokenValue(token);

            if (value.Equals("case"))
            {
                ParseConstantExpression(node);

                token = _tokenStream.Advance();

                if (!GetTokenValue(token).Equals(":"))
                {
                    _tokenStream.CurrentIndex--;
                    AddSyntaxError(token.LineNumber, "Missing ':' after 'case'.");
                }
                else
                {
                    AddTerminalNode(node, token);
                }

                ParseStatement(node);
            }
            else if (value.Equals("default"))
            {
                token = _tokenStream.Advance();

                if (!GetTokenValue(token).Equals(":"))
                {
                    _tokenStream.CurrentIndex--;
                    AddSyntaxError(token.LineNumber, "Missing ':' after 'default'.");
                }
                else
                {
                    AddTerminalNode(node, token);
                }

                ParseStatement(node);
            }
            else
            {
                AddSyntaxError(token.LineNumber, "Expected 'case' or 'default.'");
            }
        }
        
        /// <summary>
        /// 40.	primary_expression -> IDENTIFIER | CONSTANT | '(' expression ')'
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParsePrimaryExpression(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "primary_expression");

            Token token = _tokenStream.Advance();
            
            if (GetTokenValue(token).Equals("("))
            {
                AddTerminalNode(node, token);

                ParseExpression(node);

                token = _tokenStream.Advance();

                if (!GetTokenValue(token).Equals(")"))
                {
                    AddSyntaxError(token.LineNumber, "Expected ')'.");
                }
                else
                {
                    AddTerminalNode(node, token);
                }
            }
            else
            {
                if (token.Type != TokenType.Identifier && token.Type != TokenType.Constant)
                {
                    AddSyntaxError(token.LineNumber, "Identifier or constant expected.");
                }
                else
                {
                    AddTerminalNode(node, token);
                }
            }
        }

        /// <summary>
        /// 41. postfix_expression -> primary_expression postfix_expression_1
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParsePostfixExpression(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "postfix_expression");

            ParsePrimaryExpression(node);
            ParsePostfixExpression1(node);                                    
        }

        /// <summary>
        /// 42. postfix_expression_1 ->	'[' expression ']' postfix_expression_1 | '.' IDENTIFIER postfix_expression_1 | '++' postfix_expression_1 | '--' postfix_expression_1 | '(' postfix_expression_2 postfix_expression_1 | epsilon
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParsePostfixExpression1(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "postfix_expression_1");

            string value = GetTokenValue(_tokenStream.CurrentToken);

            if (value.Equals("["))
            {
                Token token = _tokenStream.Advance();
                AddTerminalNode(node, token);

                ParseExpression(node);

                token = _tokenStream.Advance();

                if (!GetTokenValue(token).Equals("]"))
                {
                    AddSyntaxError(token.LineNumber, "Opening bracket mismatch. Expected ']'.");
                }
                else
                {
                    AddTerminalNode(node, token);
                }

                ParsePostfixExpression1(node);
            }
            else if (value.Equals("."))
            {
                Token token = _tokenStream.Advance();
                AddTerminalNode(node, token);

                token = _tokenStream.Advance();

                if (token.Type != TokenType.Identifier)
                {
                    AddSyntaxError(token.LineNumber, "Identifier expected.");
                }
                else
                {
                    AddTerminalNode(node, token);
                }

                ParsePostfixExpression1(node);
            }
            else if (value.Equals("++"))
            {
                Token token = _tokenStream.Advance();
                AddTerminalNode(node, token);

                ParsePostfixExpression1(node);
            }
            else if (value.Equals("--"))
            {
                Token token = _tokenStream.Advance();
                AddTerminalNode(node, token);

                ParsePostfixExpression1(node);
            }
            else if (value.Equals("("))
            {
                Token token = _tokenStream.Advance();
                AddTerminalNode(node, token);

                ParsePostfixExpression2(node);
                ParsePostfixExpression1(node);
            }
            else
            {
                AddEpsilonNode(node);
            }
        }

        /// <summary>
        /// 43.	postfix_expression_2 ->	')' | expression ')'
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParsePostfixExpression2(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "postfix_expression_2");

            if (GetTokenValue(_tokenStream.CurrentToken).Equals(")"))
            {
                Token token = _tokenStream.Advance();
                AddTerminalNode(node, token);
            }
            else
            {
                ParseExpression(node);

                Token token = _tokenStream.Advance();

                if (!GetTokenValue(token).Equals(")"))
                {
                    AddSyntaxError(token.LineNumber, "Expected ')'.");
                }
                else
                {
                    AddTerminalNode(node, token);
                }
            }
        }

        /// <summary>
        /// 44. unary_operator -> '+' | '-' | '!'        
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseUnaryOperator(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "unary_operator");

            Token token = _tokenStream.Advance();

            if (!IsFirstUnaryOperatorToken(token))
            {
                AddSyntaxError(token.LineNumber, "Expected unary operator.");
            }
            else
            {
                AddTerminalNode(node, token);
            }
        }

        /// <summary>
        /// 45.	unary_expression ->	postfix_expression | '++' unary_expression | '--' unary_expression | unary_operator unary_expression
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseUnaryExpression(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "unary_expression");

            Token token = _tokenStream.CurrentToken;

            if (IsFirstPostfixExpressionToken(token))
            {
                ParsePostfixExpression(node);
            }
            else if (IsFirstUnaryOperatorToken(token))
            {
                ParseUnaryOperator(node);
                ParseUnaryExpression(node);
            }
            else 
            {
                string value = GetTokenValue(token);

                if (value.Equals("++") | value.Equals("--"))
                {
                    token = _tokenStream.Advance();
                    AddTerminalNode(node, token);

                    ParseUnaryExpression(node);
                }
                else
                {
                    AddSyntaxError(token.LineNumber, "Unrecognized expression.");
                }                
            }
        }

        /// <summary>
        /// 46.	multiplicative_expression -> unary_expression multiplicative_expression_1
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseMultiplicativeExpression(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "multiplicative_expression");

            ParseUnaryExpression(node);
            ParseMultiplicativeExpression1(node);
        }

        /// <summary>
        /// 47. multiplicative_expression_1 -> '*' multiplicative_expression | '/' multiplicative_expression | '%' multiplicative_expression | epsilon
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseMultiplicativeExpression1(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "multiplicative_expression_1");

            string value = GetTokenValue(_tokenStream.CurrentToken);

            if (value.Equals("*") || value.Equals("/") || value.Equals("%"))
            {
                Token token = _tokenStream.Advance();
                AddTerminalNode(node, token);

                ParseMultiplicativeExpression(node);
            }
            else
            {
                AddEpsilonNode(node);
            }
        }

        /// <summary>
        /// 48.	additive_expression -> multiplicative_expression additive_expression_1
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseAdditiveExpression(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "additive_expression");

            ParseMultiplicativeExpression(node);
            ParseAdditiveExpression1(node);
        }

        /// <summary>
        /// 49.	additive_expression_1 -> '+' additive_expression | '-' additive_expression | epsilon
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseAdditiveExpression1(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "additive_expression_1");

            string value = GetTokenValue(_tokenStream.CurrentToken);

            if (value.Equals("+") || value.Equals("-"))
            {
                Token token = _tokenStream.Advance();
                AddTerminalNode(node, token);

                ParseAdditiveExpression(node);
            }
            else
            {
                AddEpsilonNode(node);
            }
        }

        /// <summary>
        /// 50. relational_expression -> additive_expression relational_expression_1
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseRelationalExpression(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "relational_expression");

            ParseAdditiveExpression(node);
            ParseRelationalExpression1(node);
        }

        /// <summary>
        /// 51. relational_expression_1	-> LESS relational_expression | GREATER relational_expression | LESS_OR_EQUAL relational_expression | GREATER_OR_EQUAL relational_expression | epsilon
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseRelationalExpression1(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "relational_expression_1");

            string value = GetTokenValue(_tokenStream.CurrentToken);

            if (value.Equals("<") || value.Equals(">") || value.Equals("<=") || value.Equals(">="))
            {
                Token token = _tokenStream.Advance();
                AddTerminalNode(node, token);

                ParseRelationalExpression(node);
            }
            else
            {
                AddEpsilonNode(node);
            }
        }

        /// <summary>
        /// 52. equality_expression	-> relational_expression equality_expression_1
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseEqualityExpression(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "equality_expression");

            ParseRelationalExpression(node);
            ParseEqualityExpression1(node);
        }

        /// <summary>
        /// 53. equality_expression_1 -> '==' equality_expression | '!=' equality_expression | epsilon
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseEqualityExpression1(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "equality_expression_1");

            string value = GetTokenValue(_tokenStream.CurrentToken);

            if (value.Equals("==") || value.Equals("!="))
            {
                Token token = _tokenStream.Advance();
                AddTerminalNode(node, token);

                ParseEqualityExpression(node);
            }
            else
            {
                AddEpsilonNode(node);
            }
        }

        /// <summary>
        /// 54. logical_and_expression -> equality_expression logical_and_expression_1
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseLogicalAndExpression(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "logical_and_expression");

            ParseEqualityExpression(node);
            ParseLogicalAndExpression1(node);
        }

        /// <summary>
        /// 55. logical_and_expression_1 ->	'&&' logical_and_expression | epsilon
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseLogicalAndExpression1(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "logical_and_expression_1");

            string value = GetTokenValue(_tokenStream.CurrentToken);

            if (value.Equals("&&"))
            {
                Token token = _tokenStream.Advance();
                AddTerminalNode(node, token);

                ParseLogicalAndExpression(node);
            }
            else
            {
                AddEpsilonNode(node);
            }
        }

        /// <summary>
        /// 56. logical_or_expression -> logical_and_expression logical_or_expression_1
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseLogicalOrExpression(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "logical_or_expression");

            ParseLogicalAndExpression(node);
            ParseLogicalOrExpression1(node);
        }

        /// <summary>
        /// 57. logical_or_expression_1	-> '||' logical_or_expression | epsilon
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseLogicalOrExpression1(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "logical_or_expression_1");

            string value = GetTokenValue(_tokenStream.CurrentToken);

            if (value.Equals("||"))
            {
                Token token = _tokenStream.Advance();
                AddTerminalNode(node, token);

                ParseLogicalOrExpression(node);
            }
            else
            {
                AddEpsilonNode(node);
            }
        }

        /// <summary>
        /// 58. assignment_expression -> unary_expression assignment_expression_1
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseAssignmentExpression(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "assignment_expression");

            ParseUnaryExpression(node);
            ParseAssignmentExpression1(node);
        }

        /// <summary>
        /// 59. assignment_expression_1 -> assignment_operator assignment_expression | multiplicative_expression_1 additive_expression_1 relational_expression_1 equality_expression_1 logical_and_expression_1 logical_or_expression_1
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseAssignmentExpression1(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "assignment_expression_1");

            if (IsFirstAssignmentOperatorToken(_tokenStream.CurrentToken))
            {
                ParseAssignmentOperator(node);
                ParseAssignmentExpression(node);
            }
            else
            {
                ParseMultiplicativeExpression1(node);
                ParseAdditiveExpression1(node);
                ParseRelationalExpression1(node);
                ParseEqualityExpression1(node);
                ParseLogicalAndExpression1(node);
                ParseLogicalOrExpression1(node);
            }
        }

        /// <summary>
        /// 60. assignment_operator	-> '=' | '*=' | '/=' | '%=' | '+=' | '-='
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseAssignmentOperator(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "assignment_operator");
            AddTerminalNode(node, _tokenStream.Advance());
        }

        /// <summary>
        /// 61. expression -> assignment_expression expression_1
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseExpression(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "expression");

            ParseAssignmentExpression(node);
            ParseExpression1(node);
        }

        /// <summary>
        /// 62. expression_1 -> ',' expression | epsilon
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseExpression1(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "expression_1");

            if (GetTokenValue(_tokenStream.CurrentToken).Equals(","))
            {
                Token token = _tokenStream.Advance();
                AddTerminalNode(node, token);

                ParseExpression(node);
            }
            else
            {
                AddEpsilonNode(node);
            }
        }

        /// <summary>
        /// 63. constant_expression	-> logical_or_expression
        /// </summary>
        /// <param name="parent">Parent parse tree node.</param>
        private void ParseConstantExpression(TreeNode<SyntaxNode> parent)
        {
            TreeNode<SyntaxNode> node = AddNonTerminalNode(parent, "constant_expression");
            ParseLogicalOrExpression(node);
        }

        #endregion Non-Terminal Parsing Methods

        #region First Set Test Methods

        /// <summary>
        /// Tests if specified token is element of the FIRST(assignment_operator) set.
        /// </summary>
        /// <param name="token">Token to test.</param>
        /// <returns>True if token is element of the FIRST(assignment_operator) set.</returns>
        private bool IsFirstAssignmentOperatorToken(Token token)
        {
            string value = GetTokenValue(token);
            return value.Equals("=") || value.Equals("*=") || value.Equals("/=") || value.Equals("%=") || value.Equals("+=") || value.Equals("-=");
        }

        /// <summary>
        /// Tests if specified token is element of the FIRST(unary_operator) set.
        /// </summary>
        /// <param name="token">Token to test.</param>
        /// <returns>True if token is element of the FIRST(unary_operator) set.</returns>
        private bool IsFirstUnaryOperatorToken(Token token)
        {
            string value = GetTokenValue(token);
            return value.Equals("+") || value.Equals("-") || value.Equals("!");
        }

        /// <summary>
        /// Tests if specified token is element of the FIRST(postfix_expression) set.
        /// </summary>
        /// <param name="token">Token to test.</param>
        /// <returns>True if token is element of the FIRST(postfix_expression) set.</returns>
        private bool IsFirstPostfixExpressionToken(Token token)
        {
            string value = GetTokenValue(token);
            return value.Equals("(") || token.Type == TokenType.Constant || token.Type == TokenType.Identifier;
        }

        /// <summary>
        /// Tests if specified token is element of the FIRST(unary_expression) set.
        /// </summary>
        /// <param name="token">Token to test.</param>
        /// <returns>True if token is element of the FIRST(unary_expression) set.</returns>
        private bool IsFirstUnaryExpressionToken(Token token)
        {
            string value = GetTokenValue(token);
            return IsFirstUnaryOperatorToken(token) || IsFirstPostfixExpressionToken(token) || value.Equals("++") || value.Equals("--");
        }

        /// <summary>
        /// Tests if specified token is element of the FIRST(compound_statement) set.
        /// </summary>
        /// <param name="token">Token to test.</param>
        /// <returns>True if token is element of the FIRST(compound_statement) set.</returns>
        private bool IsFirstCompoundStatementToken(Token token)
        {
            return GetTokenValue(token).Equals("{");
        }

        /// <summary>
        /// Tests if specified token is element of the FIRST(iteration_statement) set.
        /// </summary>
        /// <param name="token">Token to test.</param>
        /// <returns>True if token is element of the FIRST(iteration_statement) set.</returns>
        private bool IsFirstIterationStatementToken(Token token)
        {
            return IsFirstWhileIterationStatementToken(token) || IsFirstDoIterationStatementToken(token) || IsFirstForIterationStatementToken(token);
        }

        /// <summary>
        /// Tests if specified token is element of the FIRST(while_iteration_statement) set.
        /// </summary>
        /// <param name="token">Token to test.</param>
        /// <returns>True if token is element of the FIRST(while_iteration_statement) set.</returns>
        private bool IsFirstWhileIterationStatementToken(Token token)
        {
            return GetTokenValue(token).Equals("while");
        }

        /// <summary>
        /// Tests if specified token is element of the FIRST(do_iteration_statement) set.
        /// </summary>
        /// <param name="token">Token to test.</param>
        /// <returns>True if token is element of the FIRST(do_iteration_statement) set.</returns>
        private bool IsFirstDoIterationStatementToken(Token token)
        {
            return GetTokenValue(token).Equals("do");
        }

        /// <summary>
        /// Tests if specified token is element of the FIRST(for_iteration_statement) set.
        /// </summary>
        /// <param name="token">Token to test.</param>
        /// <returns>True if token is element of the FIRST(for_iteration_statement) set.</returns>
        private bool IsFirstForIterationStatementToken(Token token)
        {
            return GetTokenValue(token).Equals("for");
        }

        /// <summary>
        /// Tests if specified token is element of the FIRST(jump_statement) set.
        /// </summary>
        /// <param name="token">Token to test.</param>
        /// <returns>True if token is element of the FIRST(jump_statement) set.</returns>
        private bool IsFirstJumpStatementToken(Token token)
        {
            string value = GetTokenValue(token);
            return value.Equals("continue") || value.Equals("break") || value.Equals("return");
        }

        /// <summary>
        /// Tests if specified token is element of the FIRST(labeled_statement) set.
        /// </summary>
        /// <param name="token">Token to test.</param>
        /// <returns>True if token is element of the FIRST(labeled_statement) set.</returns>
        private bool IsFirstLabeledStatementToken(Token token)
        {
            string value = GetTokenValue(token);
            return value.Equals("case") || value.Equals("default");
        }

        /// <summary>
        /// Tests if specified token is element of the FIRST(expression_statement) set.
        /// </summary>
        /// <param name="token">Token to test.</param>
        /// <returns>True if token is element of the FIRST(expression_statement) set.</returns>
        private bool IsFirstExpressionStatementToken(Token token)
        {
            return IsFirstUnaryExpressionToken(token);
        }

        /// <summary>
        /// Tests if specified token is element of the FIRST(selection_statement) set.
        /// </summary>
        /// <param name="token">Token to test.</param>
        /// <returns>True if token is element of the FIRST(selection_statement) set.</returns>
        private bool IsFirstSelectionStatementToken(Token token)
        {
            return IsFirstIfSelectionStatementToken(token) || IsFirstSwitchSelectionStatementToken(token);
        }

        /// <summary>
        /// Tests if specified token is element of the FIRST(if_selection_statement) set.
        /// </summary>
        /// <param name="token">Token to test.</param>
        /// <returns>True if token is element of the FIRST(if_selection_statement) set.</returns>
        private bool IsFirstIfSelectionStatementToken(Token token)
        {
            return GetTokenValue(token).Equals("if");
        }

        /// <summary>
        /// Tests if specified token is element of the FIRST(switch_selection_statement) set.
        /// </summary>
        /// <param name="token">Token to test.</param>
        /// <returns>True if token is element of the FIRST(switch_selection_statement) set.</returns>
        private bool IsFirstSwitchSelectionStatementToken(Token token)
        {
            return GetTokenValue(token).Equals("switch");
        }

        /// <summary>
        /// Tests if specified token is element of the FIRST(statement) set.
        /// </summary>
        /// <param name="token">Token to test.</param>
        /// <returns>True if token is element of the FIRST(statement) set.</returns>
        private bool IsFirstStatementToken(Token token)
        {
            return IsFirstCompoundStatementToken(token) || IsFirstExpressionStatementToken(token) || IsFirstSelectionStatementToken(token) || IsFirstIterationStatementToken(token) || IsFirstJumpStatementToken(token) || IsFirstLabeledStatementToken(token);
        }

        /// <summary>
        /// Tests if specified token is element of the FIRST(function_tail) set.
        /// </summary>
        /// <param name="token">Token to test.</param>
        /// <returns>True if token is element of the FIRST(function_tail) set.</returns>
        private bool IsFirstFunctionTailToken(Token token)
        {
            return GetTokenValue(token).Equals("(");
        }

        /// <summary>
        /// Tests if specified token is element of the FIRST(variable_tail) set.
        /// </summary>
        /// <param name="token">Token to test.</param>
        /// <returns>True if token is element of the FIRST(variable_tail) set.</returns>
        private bool IsFirstVariableTailToken(Token token)
        {
            string value = GetTokenValue(token);
            return value.Equals("[") || value.Equals(";") || value.Equals("=");
        }

        /// <summary>
        /// Tests if specified token is element of the FIRST(external_declaration) set.
        /// </summary>
        /// <param name="token">Token to test.</param>
        /// <returns>True if token is element of the FIRST(external_declaration) set.</returns>
        private bool IsFirstExternalDeclarationToken(Token token)
        {
            return IsFirstDeclarationToken(token) || IsFirstStructDefinitionToken(token);
        }

        /// <summary>
        /// Tests if specified token is element of the FIRST(declaration) set.
        /// </summary>
        /// <param name="token">Token to test.</param>
        /// <returns>True if token is element of the FIRST(declaration) set.</returns>
        private bool IsFirstDeclarationToken(Token token)
        {
            return IsFirstDeclaratorToken(token);
        }

        /// <summary>
        /// Tests if specified token is element of the FIRST(struct_definition) set.
        /// </summary>
        /// <param name="token">Token to test.</param>
        /// <returns>True if token is element of the FIRST(struct_definition) set.</returns>
        private bool IsFirstStructDefinitionToken(Token token)
        {
            return GetTokenValue(token).Equals("struct");
        }

        /// <summary>
        /// Tests if specified token is element of the FIRST(declaration_list) set.
        /// </summary>
        /// <param name="token">Token to test.</param>
        /// <returns>True if token is element of the FIRST(declaration_list) set.</returns>
        private bool IsFirstDeclarationListToken(Token token)
        {
            return IsFirstDeclaratorToken(token);
        }

        /// <summary>
        /// Tests if specified token is element of the FIRST(declarator) set.
        /// </summary>
        /// <param name="token">Token to test.</param>
        /// <returns>True if token is element of the FIRST(declarator) set.</returns>
        private bool IsFirstDeclaratorToken(Token token)
        {
            return IsFirstTypeSpecifierToken(token) && _tokenStream[_tokenStream.CurrentIndex + 1].Type == TokenType.Identifier;
        }

        /// <summary>
        /// Tests if specified token is element of the FIRST(type_specifier) set.
        /// </summary>
        /// <param name="token">Token to test.</param>
        /// <returns>True if token is element of the FIRST(type_specifier) set.</returns>
        private bool IsFirstTypeSpecifierToken(Token token)
        {
            if (token.Type == TokenType.Identifier)
                return true;

            if (token.Type != TokenType.Keyword)
                return false;

            string value = GetTokenValue(token);
            return value.Equals("void") || value.Equals("char") || value.Equals("int") || value.Equals("float") || value.Equals("double");
        }

        #endregion First Set Test Methods

        #region Parse Tree Methods

        /// <summary>
        /// Adds root parse tree node.
        /// </summary>
        /// <param name="name">Name of the non-terminal root node.</param>
        /// <returns>Root node.</returns>
        private TreeNode<SyntaxNode> AddRootNode(string name)
        {
            return new TreeNode<SyntaxNode>(new SyntaxNode(_parseTreeNodeCounter++, false, name));
        }

        /// <summary>
        /// Adds terminal node to the specified parent node.
        /// </summary>
        /// <param name="parent">Parent node.</param>
        /// <param name="token">Token representing terminal.</param>
        /// <returns>Added terminal node.</returns>
        private TreeNode<SyntaxNode> AddTerminalNode(TreeNode<SyntaxNode> parent, Token token)
        {
            return parent.Add(new SyntaxNode(_parseTreeNodeCounter++, true, GetTokenValue(token)));
        }

        /// <summary>
        /// Adds non-terminal node to the specified parent node.
        /// </summary>
        /// <param name="parent">Parent node.</param>
        /// <param name="name">Name of the non-terminal.</param>
        /// <returns>Added non-terminal node.</returns>
        private TreeNode<SyntaxNode> AddNonTerminalNode(TreeNode<SyntaxNode> parent, string name)
        {
            return parent.Add(new SyntaxNode(_parseTreeNodeCounter++, false, name));
        }

        /// <summary>
        /// Adds epsilon node to the specified parent.
        /// </summary>
        /// <param name="parent">Parent node.</param>
        /// <returns>Epsilon node.</returns>
        private TreeNode<SyntaxNode> AddEpsilonNode(TreeNode<SyntaxNode> parent)
        {
            return null;
        }

        /// <summary>
        /// Reduces parse tree by removing non-terminal nodes that do not have terminal node.
        /// </summary>
        private void ReduceParseTree()
        {
            List<TreeNode<SyntaxNode>> nodes = new List<TreeNode<SyntaxNode>>();

            DeflateTree(_parseTreeRootNode, nodes);

            foreach (TreeNode<SyntaxNode> node in nodes)
            {
                if (!node.Value.Terminal && node.Children.Count == 0)
                {
                    node.Parent = null;
                }
            }
        }

        /// <summary>
        /// Converts tree node structure to the list of nodes.
        /// </summary>
        /// <param name="parent">Parent node.</param>
        /// <param name="nodes">Result.</param>
        private void DeflateTree(TreeNode<SyntaxNode> parent, List<TreeNode<SyntaxNode>> nodes)
        {
            foreach (TreeNode<SyntaxNode> node in parent.Children)
            {
                DeflateTree(node, nodes);
            }

            nodes.Add(parent);
        }

        #endregion Parse Tree Methods

        #region Helper Methods

        /// <summary>
        /// Returns value of the specified token.
        /// </summary>
        /// <param name="token">Token.</param>
        /// <returns>Value.</returns>
        private string GetTokenValue(Token token)
        {
            return _lexerTables.GetTokenValue(token);
        }

        /// <summary>
        /// Adds new syntax error.
        /// </summary>
        /// <param name="line">Source code line.</param>
        /// <param name="description">Description.</param>
        private void AddSyntaxError(int line, string description)
        {
            AddSyntaxError(new SyntaxError(line - 1, description));
        }
        
        /// <summary>
        /// Adds new syntax error.
        /// </summary>
        /// <param name="syntaxError">Error to add.</param>
        private void AddSyntaxError(SyntaxError syntaxError)
        {
            _syntaxErrors.Add(syntaxError);
        }

        #endregion Helper Methods
    }
}